#include <iostream>

using namespace std;

class Base {
    // 添加 friend 声明,其他成员与之前的版本一致
    friend class Pal;   // Pal 在访问 Base 的派生类时不具有特殊性
protected:
    int prot_mem;   // protected 成员
    std::size_t n;
public:
    Base() : mem(0) { }
    void pub_mem(); // public 成员
    std::size_t size() const { return n; }
private:
    char priv_mem;    // private 成员
    int mem;
};

class Derived : private Base {  // private 继承
public:
    // 保持对象尺寸相关的成员的访问级别
    using Base::size;   // 改变了外部访问的级别,Derived 的用户可以访问 size
    Derived(int i) : mem(i) { } // 用 i 初始化 Derived::mem
                                // Base::mem 进行默认初始化
    int get_mem() { return mem; }   // 返回 Derived::mem
    int get_base_mem() { return Base::mem; }
protected:
    using Base::n;  // Derived 中的 n 从 private 变为 protected
    int mem;    // 隐藏基类中的 mem
};

class Sneaky : public Base {
    friend void clobber(Sneaky&);   // 能够访问 Sneaky::prot_mem
    friend void clobber(Base&);     // 不能访问 Base::prot_mem
    int j;                          // Sneaky::j 默认是 private
};
// 正确: clobber 能访问 Sneaky 对象的 protected 和 private 成员
void clobber(Sneaky &s) { s.j = s.prot_mem = 0; }
// 错误: clobber 是 Sneak 的友元,不能访问 Base 的 protected 成员
void clobber(Base &b) { b.prot_mem = 0; }

struct Pub_Derv : public Base {
    // 正确,派生类能访问 protected 成员
    int f() { return prot_mem;}
    // 错误,派生类不能访问 private 成员
    char g() { return priv_mem; }
};

struct Priv_Derv : private Base {
    // 正确,派生列表中的访问说明符不影响派生类自身访问基类的 protected 成员
    int f1() const { return prot_mem; }
};

struct Derived_from_Public : public Pub_Derv {
    // 正确: Base::prot_mem 在 Pub_Derv 中仍然是 protected 的
    int use_base() { return prot_mem; }
};

struct Derived_from_Private : public Priv_Derv {
    // 错误: Base::prot_mem 在 Priv_Derv 中是 private 的
    int use_base() { return prot_mem; }
};

class Pal {
public:
    // 正确: Pal 是 Base 的友元,能够访问 Base 的 protected 成员
    int f(Base b) { return b.prot_mem; }
    // 错误: Pal 不是 Sneaky 的友元,不能访问 Sneaky 的 private 成员
    int f2(Sneaky s) { return s.j; }
    // 正确:对基类的访问权限由基类本身控制,即使对于派生类的基类部分也是如此
    // Pal 是 Base 的友元,所以能够访问 Sneaky 中的 Base 部分
    int f3(Sneaky s) { return s.prot_mem; }
};


int main()
{
    Pub_Derv d1;    // 继承自 Base 的成员是 public 的
    Priv_Derv d2;   // 继承自 Base 的成员是 private 的
    d1.pub_mem();   // 正确: pub_mem() 在派生类中是 public 的
    d2.pub_mem();   // 错误: pub_mem() 在派生类中是 private 的
    return 0;
}
